import re
from django.shortcuts import render, redirect

from mydjango import settings
from mydjango.settings import SECRET_KEY
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View



import json
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection
from django.db.models import Avg,Min,Max,Count,Sum

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time
import datetime

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

from myapp.models import User, DingTalkUser, GiteeUser, Course, Cate,Flow,Score
from myapp.myser import UserSer, CourseSer, CateSer,FlowSer,ScoreSer

from django.utils.deprecation import MiddlewareMixin

from django.http import QueryDict

# 类视图调用
from django.utils.decorators import method_decorator

# 事务操作
from django.db import transaction

import hashlib


# 构造课程分类层级关系
def get_tree(data):
    lists = []
    tree = {}

    for item in data:
        tree[item['id']] = item

    for i in data:
        if not i['pid']:
            lists.append(tree[i['id']])
        else:
            parent_id = i['pid']
            if 'children' not in tree[parent_id]:
                tree[parent_id]['children'] = []
            tree[parent_id]['children'].append(tree[i['id']])

    return lists


# 获取课程分类
def get_cate(request):
    # 建立游标查询
    cursor = connection.cursor()
    # 执行sql
    cursor.execute('select * from cate')
    # 获取结果集
    # res = cursor.fetchall()
    res = dictfetchall(cursor)
    res = get_tree(res)

    return HttpResponse(json.dumps(res, indent=4, ensure_ascii=False), content_type='application/json')


class filter_cate(APIView):
    def get(self,request):
        cid = request.GET.get('cid')
        queryset = Cate.objects.filter(id = cid)
        ser = CateSer(queryset,many=True)
        return Response(ser.data)



# 课程分页
class CourseAPIView(APIView):
    def get(self, request):
        # 当前页
        page = request.GET.get('page', 1)

        # 每页展示条数
        size = request.GET.get('size', 1)

        r = redis.Redis()

        if r.get('list'+ str(page)):
            data = eval(str(r.get('list'+ str(page)),'utf-8'))

        else:

            # 起始位置
            data_start = int(page) - 1 * int(size)

            # 结束位置
            data_end = int(page) * int(size)

            # 查询
            courselist = Course.objects.all()[data_start:data_end]

            # 总条数
            count = Course.objects.count()

            # 序列化
            courselist_ser = CourseSer(courselist, many=True)
            data = courselist_ser.data
            r.set('list'+str(page), str(courselist_ser.data))


        return Response({'total': count, 'data': data})

    def post(self, request):
        title = request.data.get('title')
        desc = request.data.get('desc')
        price = request.data.get('price')
        video = request.data.get('video')
        cid = request.data.get('cid')
        Course.objects.create(title=title, desc=desc, price=price, video=video, cid_id=cid)
        return Response({'msg': '添加课程成功', 'code': 200})


# 课程详情
class CourseInfo(APIView):
    def get(self,request):
        r = redis.Redis(host='192.168.99.100',port=6380)
        cid = request.GET.get('cid')
        if r.get(str(id)):
            data = eval(str(r.get(id),'utf-8'))

        else:
            queryset = Course.objects.get(pk = cid)
            ser = CourseSer(queryset)
            data = ser.data
            r.set(str(id),str(ser.data))
            print(r.get(ser.data))
        return Response(data)



def dictfetchall(cursor):
    desc = cursor.description
    return [

        dict(zip([col[0] for col in desc], row))

        for row in cursor.fetchall()
    ]


# 获取某个用户的权限
class GetUserAccess(APIView):
    def get(self, request):
        # 建立游标查询
        cursor = connection.cursor()
        # 执行sql
        cursor.execute('SELECT a.username,c.node_name,c.id from USER a LEFT JOIN'
                       ' access b ON a.id = b.user_id LEFT JOIN node c on b.node_id = c.id WHERE a.id=%s' % request.uid)
        # 获取结果集
        res = cursor.fetchall()
        # res = dictfetchall(cursor)
        return Response(res)


# 钉钉第三方登录
import time
import hmac
import base64
from hashlib import sha256
import urllib
import json







# 构造钉钉登录url
def ding_url(request):
    appid = 'dingoaukgkwqknzjvamdqh'
    redirect_uri = 'http://localhost:8000/dingding_back/'

    return redirect(
        'https://oapi.dingtalk.com/connect/qrconnect?appid=' + appid + '&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=' + redirect_uri)


# 构造钉钉回调方法
def dback(request):
    # 获取code
    code = request.GET.get("code")

    t = time.time()
    # 时间戳
    timestamp = str((int(round(t * 1000))))
    appSecret = 'ly-AzMKMmCKQP3geaILT_An32kEfKO3HeOtApy5CgKwjytevVZC0WYsT2gxMB160'
    # 构造签名
    signature = base64.b64encode(
        hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())
    # 请求接口，换取钉钉用户名
    payload = {'tmp_auth_code': code}
    headers = {'Content-Type': 'application/json'}
    res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' + urllib.parse.quote(
        signature.decode("utf-8")) + "&timestamp=" + timestamp + "&accessKey=dingoaukgkwqknzjvamdqh",
                        data=json.dumps(payload), headers=headers)
    res_dict = json.loads(res.text)

    print(res_dict)
    user_info = res_dict['user_info']
    user = DingTalkUser.objects.filter(username=user_info['nick'])
    if user:
        return redirect('http://127.0.0.1:8080/dinglogin')
    else:
        user = DingTalkUser(username=res_dict['username'])
        user.save()
        user = DingTalkUser.objects.filter(username=user_info['nick'])
        return redirect('http://127.0.0.1:8080/dinglogin')


# 钉钉登录
class Dlogin(APIView):
    def post(self, request):
        username = request.data.get('username')
        DingTalkUser.objects.get(username=username)
        return Response({"msg": '登陆成功', 'code': 200})

# 码云登录
class Gitee(View):

    def get(self, request):
        return redirect(
            "https://gitee.com/oauth/authorize?client_id=ac0439431abe034ccc20a922999b58c40c5d4df1769bc3f0c8707082f9236c86&redirect_uri=http://localhost:8000/gitee_back&response_type=code")


class GiteeBack(View):

    def get(self, request):

        code = request.GET.get("code", None)

        r = requests.post(
            "https://gitee.com/oauth/token?grant_type=authorization_code&code=%s&client_id=ac0439431abe034ccc20a922999b58c40c5d4df1769bc3f0c8707082f9236c86&redirect_uri=http://localhost:8000/gitee_back&client_secret=fba28c358a9e82ff7d7672b5c171ef34707b7d1d17f4ca1b41a7e28605bfbef5" % code)
        access_token = json.loads(r.text)['access_token']

        l = requests.get("https://gitee.com/api/v5/user?access_token=" + access_token)
        name = json.loads(l.text)['name']
        user = GiteeUser.objects.filter(username=name)
        if user:
            return redirect('http://127.0.0.1:8080/giteelogin')
        else:
            user = GiteeUser(username=name)
            user.save()
            user = GiteeUser.objects.filter(username=name)
            return redirect('http://127.0.0.1:8080/giteelogin')


class Gitee_Login(APIView):
    def post(self, request):
        username = request.data.get('username')
        GiteeUser.objects.get(username=username)
        return Response({"msg": '登陆成功', 'code': 1000})


# 文件上传
class Uploader(View):

    def post(self, request):
        # 接收参数
        file = request.FILES.get('file')

        # 写文件
        with open(os.path.join(UPLOAD_ROOT, '', file.name), 'wb') as f:
            for chunk in file.chunks():
                f.write(chunk)

        return HttpResponse(json.dump({'filename': file.name}, ensure_ascii=False), content_type='application/json')


class Upimg(APIView):
    def put(self, request):
        file = request.FILES.get('file')
        user = User.objects.get(id=request.uid)
        user.img = file
        user.save()
        return Response({'上传成功'})


class downimg(APIView):
    def put(self, request):
        user = User.objects.filter(id=request.uid).update(img=None)
        return Response({'msg': '删除成功', 'code': 200})


# 定义验证码
class MyCode(View):

    # 内置类方法
    def get_random_color(self):
        # 三原色取色R,G,B
        R = random.randrange(255)
        G = random.randrange(255)
        B = random.randrange(255)

        return (R, G, B)

    def get(self, request):
        # 定义画布
        img_sizi = (120, 50)

        # 定义图像对象
        image = Image.new('RGB', img_sizi, 'white')
        # 定义画笔
        draw = ImageDraw.Draw(image, 'RGB')
        # 定义字符串
        source = 'peekaboo'
        # 定义容器
        code_str = ''

        for i in range(4):
            # 获取字符颜色
            text_color = self.get_random_color()
            # 获取随机字符
            tmp_num = random.randrange(len(source))
            random_str = source[tmp_num]
            code_str += random_str

            draw.text((10 + 30 * i, 20), random_str, text_color)

        buf = io.BytesIO()
        image.save(buf, 'png')

        # 保存验证码,将验证码保存在session中
        request.session['code'] = code_str
        print(request.session['code'])

        return HttpResponse(buf.getvalue(), 'image/png')


def make_password(mypass):
    # 生成对象
    md5 = hashlib.md5()
    # 定义加密对象
    sign_str = mypass
    # 转码
    sign_utf8 = str(sign_str).encode(encoding='utf-8')
    # 加密
    md5.update(sign_utf8)
    # 生成密文
    md5_server = md5.hexdigest()

    return md5_server


# 用户注册
class Register(APIView):

    def post(self, request):
        # 接收参数
        username = request.data.get('username', None)
        password = request.data.get('password', None)
        password1 = request.data.get('password1', None)
        email = request.data.get('email', None)
        phone = request.data.get('phone', None)
        if re.search('^1[358]\d{9}$', phone):
            if password == password1:
                user = User(username=username, password=make_password(password), phone=phone,
                            email=email)
                user.save()
                return Response({"msg": '注册成功', 'code': 1000})
            else:
                return Response({"msg": '两次密码不一致', 'code': 1001})
        else:
            return Response({"msg": '电话号码不正确', 'code': 1002})


# 用户登录
class Login(APIView):
    def post(self, request):
        # 获取验证码
        code = request.session.get('code')
        print(code, '国家提供')

        # 接受参数
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        active = request.POST.get('active')
        if active == 0:
            user = User.objects.filter(username=username).first()
            if user:
                if make_password(password) == user.password:
                    token_jwt = jwt.encode({'uid': user.id}, SECRET_KEY, algorithm='HS256')
                    token = str(token_jwt, 'utf-8')

                    return Response({"msg": '登陆成功', 'code': 1000, 'token': token})
                else:
                    return Response({"msg": '用户名或者密码错误', 'code': 1001})
            else:
                return Response({"msg": '用户名或者密码错误', 'code': 1002})
        elif active == 1:
            user = User.objects.filter(phone=username).first()
            if user:
                if make_password(password) == user.password:
                    token_jwt = jwt.encode({'uid': user.id}, SECRET_KEY, algorithm='HS256')
                    token = str(token_jwt, 'utf-8')

                    return Response({"msg": '登陆成功', 'code': 1000, 'token': token})
                else:
                    return Response({"msg": '手机号或者密码错误', 'code': 1001})
            else:
                return Response({"msg": '手机号或者密码错误', 'code': 1002})
        else:
            user = User.objects.filter(email=username).first()
            if user:
                if make_password(password) == user.password:
                    token_jwt = jwt.encode({'uid': user.id}, SECRET_KEY, algorithm='HS256')
                    token = str(token_jwt, 'utf-8')

                    return Response({"msg": '登陆成功', 'code': 1000, 'token': token})
                else:
                    return Response({"msg": '邮箱或者密码错误', 'code': 1001})
            else:
                return Response({"msg": '邮箱或者密码错误', 'code': 1002})


# 获取用户信息
class UserAPIView(APIView):
    def get(self, request):
        queryset = User.objects.filter(id=request.uid)
        ser = UserSer(queryset, many=True)
        return Response(ser.data)

    def put(self, request):
        password = request.data.get('password')
        uid = request.data.get('uid')
        user = User.objects.get(id=uid)
        user.password = make_password(password)
        user.save()
        return Response({'msg': '修改成功,请登录', 'code': 1000})

class GetFlow(APIView):
    def get(self, request):
        cid = request.GET.get('cid')
        obj = Flow.objects.filter(user_id=request.uid, course_id=cid).first()
        if obj:
            return Response({'state': 'true'})
        else:
            return Response({'state': 'false'})

    def post(self, request):
        cid = request.data.get('cid')
        Flow.objects.create(user_id=request.uid, course_id=cid)
        return Response({'msg': '关注成功', 'code': 1000})

    def delete(self,request):
        cid = request.GET.get('cid')
        Flow.objects.filter(user_id=request.uid,course_id=cid).delete()
        return Response({'msg':'取关成功','code':1000})


class show_flow(APIView):
    def get(self,request):
        queryset = Flow.objects.filter(user_id=request.uid)
        ser = FlowSer(queryset,many=True)
        return Response(ser.data)


class GetScore(APIView):
    def get(self, request):
        cid = request.GET.get('cid')
        queryset = Score.objects.filter(course_id=cid,user_id=request.uid)
        ser = ScoreSer(queryset,many=True)
        return Response(ser.data)

    def put(self,request):
        cid = request.data.get('cid')
        value = request.data.get('value')
        if Score.objects.filter(user_id=request.uid,course_id=cid):
            Score.objects.filter(user_id=request.uid,course_id=cid).update(score=value)
            return Response({'修改成功'})
        else:
            Score.objects.create(user_id=request.uid, course_id=cid, score=value)
            return Response({'打分成功'})


class AvgScore(APIView):
    def get(self,request):
        cid = request.GET.get('cid')
        queryset = Score.objects.filter(course_id=cid)
        avg = queryset.aggregate(Avg('score'))
        return Response({'avg':avg})

from django.utils.deprecation import MiddlewareMixin


class MyLoginMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        path = request.path.lstrip('/')  # 当前访问的地址
        urls = settings.EXEMPT_LOGIN_URLS
        not_match = True
        for url in urls:
            rule = re.compile(url)
            if rule.match(path):  # 满足exempt规则，不需要登录
                return
                # not_match = False
        if hasattr(request, 'user') and request.user.is_authenticated:  # 如果是已经登录状态
            return
        else:
            print(path)
            print('login required')
            return redirect('/datingsystem/login/')

    def process_response(self, request, response):
        return Response
